


#include <stdlib.h>
#include <iostream>
#include "person.h"



using namespace std;



// PersonType ::



PersonType::PersonType( eType type )
    : m_nType(type)
{
}



PersonType::PersonType( const PersonType &type )
    : m_nType(type.m_nType)
{
}



const char * const PersonType::getText() const
{
    switch( m_nType )
    {
    case VAMPIRE:
        return "vampire";
    case HUMAN:
        return "human";
    case WIZARD:
        return "wizard";
    default:
        return NULL;
    }
}



// Person ::



void Person::putText( ostream &S ) const
{
    S << '#' << getName() << ';' <<
        getType().getText() << ';' <<
        getColor().getText() << ';' <<
        ( tellsTruth() ?  "1;" : "0;" ) << 
        ( isIncognito() ?  "1;" : "0;" ) <<
        ( isFat() ?  "1" : "0" ) << endl;
}



Person::Person( const char * name, PersonType::eType type, bool anonym, bool fat, bool truth, Color::eColor col )
    : Subject( truth, col )
    , m_Type(type)
    , m_PendingType(type)
    , m_bIncognito(anonym)
    , m_bFat(fat)
    , m_pName(name)
    , m_pPendingName(name)
{
    switch( PersonType::eType(type) )
    {
    case PersonType::HUMAN:
        m_bTruth = m_bPendingTruth = truth;
        break;
        
    case PersonType::VAMPIRE: // always lies
        m_bTruth = m_bPendingTruth = false;
        break;
        
    case PersonType::WIZARD: // always tells truth
        m_bTruth = m_bPendingTruth = true;
        break;
    }
}
    


bool Person::isLikeInitial() const
{
    return m_PendingType == m_Type;
}



bool Person::mutate()
{
    switch( m_PendingType )
    {
    case PersonType::HUMAN:
        if( !Subject::mutate() )
            return false;
        if( isIncognito() )
        {
            m_PendingType = PersonType::WIZARD;
            m_bPendingTruth = true;
        }
        break;
        
    case PersonType::WIZARD:
        if( isIncognito() )
        {
            m_PendingType = PersonType::VAMPIRE;
            m_bPendingTruth = false;
        }
        break;
        
    case PersonType::VAMPIRE:
        if( isIncognito() )
        {
            m_PendingType = PersonType::HUMAN;
            m_bPendingTruth = m_bTruth;
        }
        break;
    }
    if( m_Type == m_PendingType )
        return true;
    else
        return false;
}



void Person::restore()
{
    m_bPendingTruth = m_bTruth;
    m_PendingType = m_Type;
    m_pPendingName = m_pName;
}



const char *Person::getRandomName()
{
    const char * const names[] = { "Bob", "Sam", "Peter", "John", "George", "Mike", "Alex", "Jim", "Ray", "Harry", "Vlad", "Chris", NULL };
    static list <uint8_t> idxs;
    
    if( idxs.empty() )
    {
        // filling in the indexes list
        for( uint8_t i = 0; names[i]; ++i )
            idxs.push_back(i);
    }

    // selecting one element randomly
    list <uint8_t>::iterator iidx = idxs.begin();
    for( uint8_t i = rand() % idxs.size(); i; --i )
        ++iidx;
    
    const char *ret = names[*iidx];
    idxs.erase(iidx);
    return ret;
}
